const express = require("express");
const router = express.Router();

const { success, failure } = require("../../utils/responses");
const { userInfo } = require("../../utils/userInfo");
const {
  productionInfo,
  updateProductionByIdToPalletCode,
  getAllProductions,
} = require("../../utils/getProduction");
const { ipInfoSingle } = require("../../utils/handleIp");
const { setSocket } = require("../../utils/msgSave");
const { getSocketInstance } = require("../../socket/socketInfo");
const { plcArrivalSignal } = require("../../modbusConnect/index");

const { tcpClients } = require("../../tcpConnect/index");

const {
  wcsUrl,
  wcsSnAllPalletizingApi,
  wcsData,
  wcsPlcManualOperation,
} = require("../../utils/config");

const {
  modbusStatusHandle,
  queue,
} = require("../../modbusConnect/modbusBuness");

const logger = require("../../utils/loggers"); // 引入日志模块

let socket = null;
const service = require("../../utils/request");

async function plcManualOperationHandle(data) {
  logger.info(`plcManualOperationHandle: ${JSON.stringify(data)}`);
  const url = wcsUrl + wcsPlcManualOperation + "/" + data.startDeviceId;
  logger.info(`WCS URL: ${url}`);

  try {
    const response = await fetch(url, {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
      },
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const responseData = await response.json();
    logger.info(
      `plcManualOperationHandle response: ${JSON.stringify(responseData)}`
    );
    return responseData;
  } catch (error) {
    logger.error(`Error in plcManualOperationHandle: ${error.message}`);
    throw error;
  }
}

const proDataList = [
  // {
  //   timestamp: "Invalid date",
  //   createdAt: "2025-07-25 09:50:23",
  //   updatedAt: "2025-08-08 17:59:23",
  //   id: 107,
  //   palletCode: "1000035",
  //   sizeRuleId: "8",
  //   long: "700",
  //   wide: "700",
  //   height: "700",
  //   presetsNum: "1",
  //   layerNum: "1",
  //   palletizingNum: "1",
  //   grippingDirection: "1",
  //   leftAndRightFaultToleranceNum: "8",
  //   faultToleranceBeforeAndAfterNum: "8",
  //   userId: 1,
  //   userName: "admin",
  //   beUsed: "2",
  //   lineName: "A",
  //   status: "0",
  //   sn: "1240642950005EC20606",
  //   productCode: "642922507A",
  //   sono: "so001",
  //   soline: "1",
  //   weight: "10.23",
  //   deletedAt: null,
  //   user: {
  //     id: 1,
  //     username: "admin",
  //   },
  // },
  // {
  //   timestamp: "Invalid date",
  //   createdAt: "2025-07-24 10:07:12",
  //   updatedAt: "2025-08-08 17:59:23",
  //   id: 106,
  //   palletCode: "1000034",
  //   sizeRuleId: "8",
  //   long: "700",
  //   wide: "700",
  //   height: "700",
  //   presetsNum: "1",
  //   layerNum: "1",
  //   palletizingNum: "1",
  //   grippingDirection: "1",
  //   leftAndRightFaultToleranceNum: "8",
  //   faultToleranceBeforeAndAfterNum: "8",
  //   userId: 1,
  //   userName: "admin",
  //   beUsed: "2",
  //   lineName: "B",
  //   status: "0",
  //   sn: "1240642950005EC20605",
  //   productCode: "642922506A",
  //   sono: "so001",
  //   soline: "1",
  //   weight: "101",
  //   deletedAt: null,
  //   user: {
  //     id: 1,
  //     username: "admin",
  //   },
  // },
  // {
  //   timestamp: "Invalid date",
  //   createdAt: "2025-08-03 14:03:02",
  //   updatedAt: "2025-08-11 16:51:54",
  //   id: 116,
  //   palletCode: "100504",
  //   sizeRuleId: "12",
  //   long: "1180",
  //   wide: "785",
  //   height: "930",
  //   presetsNum: "1",
  //   layerNum: "1",
  //   palletizingNum: "1",
  //   grippingDirection: "1",
  //   leftAndRightFaultToleranceNum: "12",
  //   faultToleranceBeforeAndAfterNum: "32",
  //   userId: 1,
  //   userName: "admin",
  //   beUsed: "4",
  //   lineName: "B",
  //   status: "0",
  //   sn: "1240642950005EC20615",
  //   productCode: "642922500A",
  //   sono: "so001",
  //   soline: "1",
  //   weight: "10.23",
  //   deletedAt: null,
  //   user: {
  //     id: 1,
  //     username: "admin",
  //   },
  // },
  // {
  //   timestamp: "Invalid date",
  //   createdAt: "2025-08-03 14:03:02",
  //   updatedAt: "2025-08-11 16:51:54",
  //   id: 115,
  //   palletCode: "100312",
  //   sizeRuleId: "12",
  //   long: "1180",
  //   wide: "785",
  //   height: "930",
  //   presetsNum: "1",
  //   layerNum: "1",
  //   palletizingNum: "1",
  //   grippingDirection: "1",
  //   leftAndRightFaultToleranceNum: "12",
  //   faultToleranceBeforeAndAfterNum: "32",
  //   userId: 1,
  //   userName: "admin",
  //   beUsed: "4",
  //   lineName: "A",
  //   status: "0",
  //   sn: "1240642950005EC20614",
  //   productCode: "642922500A",
  //   sono: "so001",
  //   soline: "1",
  //   weight: "10.23",
  //   deletedAt: null,
  //   user: {
  //     id: 1,
  //     username: "admin",
  //   },
  // },
  // {
  //   timestamp: "Invalid date",
  //   createdAt: "2025-08-03 14:03:02",
  //   updatedAt: "2025-08-11 16:51:54",
  //   id: 114,
  //   palletCode: "1000082",
  //   sizeRuleId: "12",
  //   long: "1180",
  //   wide: "785",
  //   height: "930",
  //   presetsNum: "1",
  //   layerNum: "1",
  //   palletizingNum: "1",
  //   grippingDirection: "1",
  //   leftAndRightFaultToleranceNum: "12",
  //   faultToleranceBeforeAndAfterNum: "32",
  //   userId: 1,
  //   userName: "admin",
  //   beUsed: "4",
  //   lineName: "B",
  //   status: "0",
  //   sn: "1240642950005EC20613",
  //   productCode: "642922500A",
  //   sono: "so001",
  //   soline: "1",
  //   weight: "10.23",
  //   deletedAt: null,
  //   user: {
  //     id: 1,
  //     username: "admin",
  //   },
  // },
  // {
  //   timestamp: "Invalid date",
  //   createdAt: "2025-08-02 15:49:17",
  //   updatedAt: "2025-08-11 16:51:54",
  //   id: 113,
  //   palletCode: "100312",
  //   sizeRuleId: "12",
  //   long: "1180",
  //   wide: "785",
  //   height: "930",
  //   presetsNum: "1",
  //   layerNum: "1",
  //   palletizingNum: "1",
  //   grippingDirection: "1",
  //   leftAndRightFaultToleranceNum: "12",
  //   faultToleranceBeforeAndAfterNum: "32",
  //   userId: 1,
  //   userName: "admin",
  //   beUsed: "4",
  //   lineName: "A",
  //   status: "0",
  //   sn: "1240642950005EC20612",
  //   productCode: "642922500A",
  //   sono: "so001",
  //   soline: "1",
  //   weight: "10.23",
  //   deletedAt: null,
  //   user: {
  //     id: 1,
  //     username: "admin",
  //   },
  // },
  {
    timestamp: "Invalid date",
    createdAt: "2025-08-03 14:03:02",
    updatedAt: "2025-08-11 18:54:17",
    id: 116,
    palletCode: "100504",
    sizeRuleId: "12",
    long: "1180",
    wide: "785",
    height: "930",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "12",
    faultToleranceBeforeAndAfterNum: "32",
    userId: 1,
    userName: "admin",
    beUsed: "4",
    lineName: "B",
    status: "0",
    sn: "1240642950005EC20615",
    productCode: "642922500A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-08-03 14:03:02",
    updatedAt: "2025-08-11 18:54:17",
    id: 115,
    palletCode: "100312",
    sizeRuleId: "12",
    long: "1180",
    wide: "785",
    height: "930",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "12",
    faultToleranceBeforeAndAfterNum: "32",
    userId: 1,
    userName: "admin",
    beUsed: "4",
    lineName: "A",
    status: "0",
    sn: "1240642950005EC20614",
    productCode: "642922500A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-08-03 14:03:02",
    updatedAt: "2025-08-11 18:54:17",
    id: 114,
    palletCode: "1000082",
    sizeRuleId: "12",
    long: "1180",
    wide: "785",
    height: "930",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "12",
    faultToleranceBeforeAndAfterNum: "32",
    userId: 1,
    userName: "admin",
    beUsed: "4",
    lineName: "B",
    status: "0",
    sn: "1240642950005EC20613",
    productCode: "642922500A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-08-02 15:49:17",
    updatedAt: "2025-08-11 18:54:17",
    id: 113,
    palletCode: "100312",
    sizeRuleId: "12",
    long: "1180",
    wide: "785",
    height: "930",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "12",
    faultToleranceBeforeAndAfterNum: "32",
    userId: 1,
    userName: "admin",
    beUsed: "4",
    lineName: "A",
    status: "0",
    sn: "1240642950005EC20612",
    productCode: "642922500A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-08-01 14:58:30",
    updatedAt: "2025-08-11 18:54:17",
    id: 112,
    palletCode: "1000080",
    sizeRuleId: "11",
    long: "1180",
    wide: "789",
    height: "920",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "2",
    leftAndRightFaultToleranceNum: "30",
    faultToleranceBeforeAndAfterNum: "30",
    userId: 1,
    userName: "admin",
    beUsed: "3",
    lineName: "B",
    status: "0",
    sn: "1240642950005EC20611",
    productCode: "642922500A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-08-01 14:30:19",
    updatedAt: "2025-08-11 18:54:17",
    id: 111,
    palletCode: "100497",
    sizeRuleId: "10",
    long: "980",
    wide: "600",
    height: "920",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "100",
    faultToleranceBeforeAndAfterNum: "100",
    userId: 1,
    userName: "admin",
    beUsed: "3",
    lineName: "A",
    status: "0",
    sn: "1240642950005EC20610",
    productCode: "642922500A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-07-31 15:09:20",
    updatedAt: "2025-08-11 18:54:17",
    id: 110,
    palletCode: "2",
    sizeRuleId: "8",
    long: "505",
    wide: "510",
    height: "705",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "8",
    faultToleranceBeforeAndAfterNum: "8",
    userId: 1,
    userName: "admin",
    beUsed: "3",
    lineName: "B",
    status: "0",
    sn: "1240642950005EC20609",
    productCode: "642922500A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "2025-07-27 16:19:35",
    createdAt: "2025-07-27 16:19:39",
    updatedAt: "2025-08-11 18:54:17",
    id: 109,
    palletCode: "1000038",
    sizeRuleId: "8",
    long: "700",
    wide: "700",
    height: "700",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "8",
    faultToleranceBeforeAndAfterNum: "8",
    userId: 1,
    userName: "admin",
    beUsed: "3",
    lineName: "A",
    status: "0",
    sn: "1240642950005EC20608",
    productCode: "6429225210A",
    sono: "SO001",
    soline: "1",
    weight: "10",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-07-25 09:51:55",
    updatedAt: "2025-08-11 18:54:17",
    id: 108,
    palletCode: "1000036",
    sizeRuleId: "8",
    long: "700",
    wide: "700",
    height: "700",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "8",
    faultToleranceBeforeAndAfterNum: "8",
    userId: 1,
    userName: "admin",
    beUsed: "2",
    lineName: "B",
    status: "0",
    sn: "1240642950005EC20607",
    productCode: "642922508A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-07-25 09:50:23",
    updatedAt: "2025-08-11 18:54:17",
    id: 107,
    palletCode: "1000035",
    sizeRuleId: "8",
    long: "700",
    wide: "700",
    height: "700",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "8",
    faultToleranceBeforeAndAfterNum: "8",
    userId: 1,
    userName: "admin",
    beUsed: "2",
    lineName: "A",
    status: "0",
    sn: "1240642950005EC20606",
    productCode: "642922507A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-07-24 10:07:12",
    updatedAt: "2025-08-11 18:54:17",
    id: 106,
    palletCode: "1000034",
    sizeRuleId: "8",
    long: "700",
    wide: "700",
    height: "700",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "8",
    faultToleranceBeforeAndAfterNum: "8",
    userId: 1,
    userName: "admin",
    beUsed: "2",
    lineName: "B",
    status: "0",
    sn: "1240642950005EC20605",
    productCode: "642922506A",
    sono: "so001",
    soline: "1",
    weight: "101",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "Invalid date",
    createdAt: "2025-07-24 10:05:22",
    updatedAt: "2025-08-11 18:54:17",
    id: 105,
    palletCode: "1000033",
    sizeRuleId: "8",
    long: "700",
    wide: "700",
    height: "700",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "8",
    faultToleranceBeforeAndAfterNum: "8",
    userId: 1,
    userName: "admin",
    beUsed: "2",
    lineName: "A",
    status: "0",
    sn: "1240642950005EC20604",
    productCode: "642922505A",
    sono: "so001",
    soline: "1",
    weight: "10.23",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "2025-05-21 15:44:18",
    createdAt: "2025-05-21 15:44:18",
    updatedAt: "2025-08-11 18:54:17",
    id: 32,
    palletCode: "100120",
    sizeRuleId: "1",
    long: "700",
    wide: "700",
    height: "700",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "32",
    faultToleranceBeforeAndAfterNum: "32",
    userId: 1,
    userName: "admin",
    beUsed: "1",
    lineName: "B",
    status: "0",
    sn: "1240642950005EC20603",
    productCode: "642922504A",
    sono: "32",
    soline: "32",
    weight: "32",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "2025-05-21 15:44:18",
    createdAt: "2025-05-21 15:44:18",
    updatedAt: "2025-08-11 18:54:17",
    id: 31,
    palletCode: "100523",
    sizeRuleId: "1",
    long: "700",
    wide: "700",
    height: "700",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "31",
    faultToleranceBeforeAndAfterNum: "31",
    userId: 1,
    userName: "admin",
    beUsed: "1",
    lineName: "A",
    status: "0",
    sn: "1240642950005EC20602",
    productCode: "642922503A",
    sono: "31",
    soline: "31",
    weight: "31",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "2025-05-21 15:44:18",
    createdAt: "2025-05-21 15:44:18",
    updatedAt: "2025-08-11 18:54:17",
    id: 30,
    palletCode: "100120",
    sizeRuleId: "1",
    long: "700",
    wide: "700",
    height: "700",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "30",
    faultToleranceBeforeAndAfterNum: "30",
    userId: 1,
    userName: "admin",
    beUsed: "1",
    lineName: "B",
    status: "0",
    sn: "1240642950005EC20601",
    productCode: "642922502A",
    sono: "30",
    soline: "30",
    weight: "30",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
  {
    timestamp: "2025-05-21 15:44:18",
    createdAt: "2025-05-21 15:44:18",
    updatedAt: "2025-08-11 18:54:17",
    id: 29,
    palletCode: "1000029",
    sizeRuleId: "1",
    long: "700",
    wide: "700",
    height: "700",
    presetsNum: "1",
    layerNum: "1",
    palletizingNum: "1",
    grippingDirection: "1",
    leftAndRightFaultToleranceNum: "29",
    faultToleranceBeforeAndAfterNum: "29",
    userId: 1,
    userName: "admin",
    beUsed: "1",
    lineName: "A",
    status: "0",
    sn: "1240642950005EC20600",
    productCode: "642922501A",
    sono: "29",
    soline: "29",
    weight: "29",
    deletedAt: null,
    user: {
      id: 1,
      username: "admin",
    },
  },
];

// 创建4个队列来存储请求参数，根据beUsed区分
const MAX_QUEUES = 4;
let requestQueues = Array(MAX_QUEUES)
  .fill()
  .map(() => []);
let isProcessings = Array(MAX_QUEUES).fill(false);

// 用于跟踪在轮询过程中已经执行过getProduction的SN码，每个队列一个Set
let pollingProcessedSNs = Array(MAX_QUEUES)
  .fill()
  .map(() => new Set());

// 轮询间隔配置（毫秒）- 保持合理的轮询间隔
const POLLING_INTERVAL = process.env.PALLETIZING_POLLING_INTERVAL || 100;

// 缓存产品信息以提高性能
const productInfoCache = new Map();
const CACHE_TTL = 5000; // 5秒缓存时间

// 入队方法
async function enqueueRequest(requestData) {
  const queueIndex = requestData.beUsed - 1;
  // 确保队列索引在有效范围内
  if (queueIndex < 0 || queueIndex >= MAX_QUEUES) {
    logger.warn(`无效的beUsed值: ${requestData.beUsed}`);
    return;
  }

  // 检查队列中是否已存在相同的SN，避免重复处理
  const existingIndex = requestQueues[queueIndex].findIndex(
    (item) => item.sn === requestData.sn
  );
  if (existingIndex === -1) {
    requestQueues[queueIndex].push(requestData);
    logger.info(
      `请求已加入队列${requestData.beUsed}，SN: ${requestData.sn}，当前队列长度: ${requestQueues[queueIndex].length}`
    );
  } else {
    logger.info(
      `SN: ${requestData.sn} 已在队列${requestData.beUsed}中，跳过重复请求`
    );
  }
}

// 处理队列中的下一个请求
async function processNextRequest(queueIndex) {
  // 验证队列索引
  if (queueIndex < 0 || queueIndex >= MAX_QUEUES) {
    logger.error(`无效的队列索引: ${queueIndex}`);
    return;
  }

  // 确保同一时间只有一个请求在处理
  if (isProcessings[queueIndex]) {
    logger.info(`队列${queueIndex + 1}正在处理中，等待完成`);
    return;
  }

  if (requestQueues[queueIndex].length === 0) {
    isProcessings[queueIndex] = false;
    logger.info(`队列${queueIndex + 1}为空，停止处理`);
    return;
  }

  // 设置处理状态为true，确保同一时间只有一个请求在处理
  isProcessings[queueIndex] = true;
  const currentRequest = requestQueues[queueIndex][0];

  try {
    await processRequest(currentRequest, queueIndex);
  } catch (error) {
    logger.error(`处理请求时出错: ${error.message}`);
    // 出错时也移除请求，避免阻塞队列
    requestQueues[queueIndex].shift();
    isProcessings[queueIndex] = false;
    // 检查所有队列是否有待处理任务
    checkAllQueues();
  }
}

// 实际处理请求的函数
async function processRequest(requestData, queueIndex) {
  const { sn, long, wide, height, beUsed, user, req, res } = requestData;

  logger.info(
    `开始处理请求，SN: ${sn}, 长: ${long}, 宽: ${wide}, 高: ${height}, beUsed: ${beUsed}`
  );

  let content = "已经接收到码垛信息,正在进行处理";
  if (!socket) {
    socket = await getSocketInstance();
  }

  try {
    // 发送日志信息 - 异步执行，不阻塞主流程
    setSocket(socket, "码垛信息", content, user.id, sn).catch((socketError) => {
      logger.error(`发送Socket消息失败: ${socketError.message}`);
    });
  } catch (socketError) {
    logger.error(`发送Socket消息失败: ${socketError.message}`);
  }

  try {
    // 查找sn 对应的产品信息 - 使用缓存优化
    const cacheKey = `${sn}-${long}-${wide}-${height}-${beUsed}`;
    let result;

    // 检查缓存
    if (productInfoCache.has(cacheKey)) {
      const cached = productInfoCache.get(cacheKey);
      if (Date.now() - cached.timestamp < CACHE_TTL) {
        result = cached.data;
        logger.info(`使用缓存的产品信息，SN: ${sn}`);
      } else {
        // 缓存过期，删除
        productInfoCache.delete(cacheKey);
      }
    }

    // 如果没有缓存，则查询数据库
    if (!result) {
      result = await productionInfo(sn, long, wide, height);
      // 存储到缓存
      productInfoCache.set(cacheKey, {
        data: result,
        timestamp: Date.now(),
      });
    }

    const { count, rows } = result;

    if (count == 0) {
      // 没有找到对应的产品信息
      content = "sn: " + sn + " 的产品未找到。";
      try {
        // 异步发送日志信息，不阻塞主流程
        setSocket(socket, "码垛信息", content, user.id, sn).catch(
          (socketError) => {
            logger.error(`发送Socket消息失败: ${socketError.message}`);
          }
        );
      } catch (socketError) {
        logger.error(`发送Socket消息失败: ${socketError.message}`);
      }
      success(req, res, content, {});

      // 处理完当前请求后，继续处理队列中的下一个请求
      requestQueues[queueIndex].shift(); // 出队当前请求
      logger.info(
        `请求已处理完成并出队，SN: ${sn}，剩余队列${queueIndex + 1}长度: ${
          requestQueues[queueIndex].length
        }`
      );
      isProcessings[queueIndex] = false;

      // 清除该SN的缓存
      clearCacheForSN(sn, long, wide, height, beUsed);

      // 检查所有队列是否有待处理任务
      checkAllQueues();
      return;
    }

    // 找到了对应的产品信息
    content = "查找sn对应的产品信息成功";
    const productionData = await getData(rows[0].dataValues);
    logger.info(`productionData: ${JSON.stringify(productionData)}`);

    try {
      // 异步发送日志信息，不阻塞主流程
      setSocket(
        socket,
        "码垛信息",
        content,
        user.id,
        JSON.stringify(productionData)
      ).catch((socketError) => {
        logger.error(`发送Socket消息失败: ${socketError.message}`);
      });
    } catch (socketError) {
      logger.error(`发送Socket消息失败: ${socketError.message}`);
    }

    // 获取产品信息 且产品是未完成状态
    if (productionData.status == 0) {
      // 检查robotStatus和robotPosition是否都为1 robotOneFinished 不是1
      const {
        robotStatus,
        robotPosition,
        robotOneFinished,
        robotOneFinishedFlag,
      } = modbusStatusHandle(productionData.beUsed - 1);

      // 立即返回响应，不等待任何Modbus操作完成
      let TaskStatus = 0;
      if (robotStatus == 1 && robotPosition == 1) {
        // 等待告知商品信息
        TaskStatus = 1;
      } else if (
        robotStatus == 1 &&
        robotPosition == 2 &&
        typeof robotPhotoStatus !== "undefined" &&
        robotPhotoStatus == 1 &&
        robotOneFinished != 1
      ) {
        // 等待拍照
        TaskStatus = 2;
      } else if (
        robotStatus == 1 &&
        robotPosition == 1 &&
        robotOneFinished == 1
      ) {
        // 码垛完成
        TaskStatus = 3;
      }

      // 成功 返回接口
      let succeData = JSON.parse(JSON.stringify(rows[0].dataValues));
      succeData.proStatus = succeData.status;
      delete succeData.status;

      let productionDataConnect = {
        code: productionData.beUsed,
        TaskNo: productionData.sn,
        ...rows[0].dataValues,
        DeviceType: 13, // 设备类型
        FromPosition: productionData.lineName, // 取货工位
        TargetPosition: productionData.lineName, // 放货工位
        TaskStatus: TaskStatus, // 任务状态
        TaskType: "2", // 任务类型
        status: robotStatus, // 设备状态
      };

      // 立即返回成功接口，不等待任何操作完成
      success(req, res, content, productionDataConnect);

      // 在后台异步执行所有Modbus相关操作
      if (robotStatus == 1 && robotPosition == 1) {
        // 异步执行getProduction，不阻塞主流程返回
        setImmediate(() => {
          getProduction(req, sn, user.id, socket, rows[0].dataValues)
            .then(() => {
              logger.info(`getProduction 已执行，SN: ${sn}`);
            })
            .catch((error) => {
              logger.error(`getProduction 执行出错: ${error.message}`);
            });
        });
        logger.info(`getProduction 已安排执行，SN: ${sn}`);
      } else {
        logger.info(
          `SN: ${sn} robotStatus: ${robotStatus}, robotPosition: ${robotPosition}，不满足条件，跳过执行getProduction`
        );
      }
      // 启动轮询检查status状态
      startPollingStatus(requestData, queueIndex);
    } else {
      success(req, res, "该商品已经完成码垛，无需再次操作", {});
      // 即使商品已完成，也需要出队
      requestQueues[queueIndex].shift(); // 出队当前请求
      logger.info(
        `请求已处理完成并出队，SN: ${sn}，剩余队列${queueIndex + 1}长度: ${
          requestQueues[queueIndex].length
        }`
      );
      isProcessings[queueIndex] = false;

      // 清除该SN的缓存
      clearCacheForSN(sn, long, wide, height, beUsed);

      // 检查所有队列是否有待处理任务
      checkAllQueues();
    }
  } catch (error) {
    logger.error(`处理产品信息时出错: ${error.message}`);
    failure(req, res, error);
    // 出错时也移除请求，避免阻塞队列
    requestQueues[queueIndex].shift();
    isProcessings[queueIndex] = false;

    // 清除该SN的缓存
    clearCacheForSN(sn, long, wide, height, beUsed);

    checkAllQueues();
  }
}

// 轮询检查数据库中的status状态
async function startPollingStatus(requestData, queueIndex) {
  // 验证队列索引
  if (queueIndex < 0 || queueIndex >= MAX_QUEUES) {
    logger.error(`轮询时遇到无效的队列索引: ${queueIndex}`);
    return;
  }

  const interval = setInterval(async () => {
    try {
      const { sn, long, wide, height, req, res, user, beUsed } = requestData;

      // 查询数据库中的最新状态 - 使用缓存优化
      const cacheKey = `${sn}-${long}-${wide}-${height}-${beUsed}`;
      let result;

      // 检查缓存
      if (productInfoCache.has(cacheKey)) {
        const cached = productInfoCache.get(cacheKey);
        if (Date.now() - cached.timestamp < CACHE_TTL) {
          result = cached.data;
          logger.info(`轮询中使用缓存的产品信息，SN: ${sn}`);
        } else {
          // 缓存过期，删除
          productInfoCache.delete(cacheKey);
        }
      }

      // 如果没有缓存，则查询数据库
      if (!result) {
        result = await productionInfo(sn, long, wide, height);
        // 存储到缓存
        productInfoCache.set(cacheKey, {
          data: result,
          timestamp: Date.now(),
        });
      }

      const { count, rows } = result;

      if (count > 0) {
        const productionData = await getData(rows[0].dataValues);
        logger.info(`轮询检查SN: ${sn}, status: ${productionData.status}`);

        // 如果status为1，则出队并处理下一个请求
        if (productionData.status == 1) {
          clearInterval(interval);
          const processedRequest = requestQueues[queueIndex].shift();
          logger.info(
            `请求已处理完成并出队，SN: ${processedRequest.sn}，剩余队列${
              queueIndex + 1
            }长度: ${requestQueues[queueIndex].length}`
          );
          // 从轮询已处理集合中移除该SN
          pollingProcessedSNs[queueIndex].delete(sn);
          isProcessings[queueIndex] = false;

          // 清除该SN的缓存，确保下个请求不会使用旧数据
          clearCacheForSN(sn, long, wide, height, beUsed);

          // 检查所有队列是否有待处理任务
          checkAllQueues();
        } else if (productionData.status == 0) {
          // 如果status仍然为0，检查robotStatus和robotPosition是否都为1
          const {
            robotStatus,
            robotPosition,
            robotOneFinished,
            robotOneFinishedFlag,
            finishOneFlagObj,
          } = modbusStatusHandle(productionData.beUsed - 1);
          logger.info(`码垛线完成情况${JSON.stringify(finishOneFlagObj)}`);

          if (robotStatus == 1 && robotPosition == 1 && !robotOneFinishedFlag) {
            // 只有当robotStatus和robotPosition都为1时，才考虑执行getProduction
            if (!pollingProcessedSNs[queueIndex].has(sn)) {
              pollingProcessedSNs[queueIndex].add(sn);
              // 在轮询过程中发现status为0且满足条件时，执行getProduction
              await getProduction(req, sn, user.id, socket, rows[0].dataValues);
              logger.info(`轮询中getProduction已执行，SN: ${sn}`);
            } else {
              logger.info(`SN: ${sn} 在轮询中已执行过getProduction，跳过`);
            }
          } else {
            logger.info(
              `轮询中SN: ${sn} robotStatus: ${robotStatus}, robotPosition: ${robotPosition}, robotOneFinishedFlag: ${robotOneFinishedFlag}，不满足条件，跳过执行getProduction`
            );
            // 如果条件不满足，从已处理集合中移除，以便条件满足时可以再次执行
            pollingProcessedSNs[queueIndex].delete(sn);
          }
        }
      } else {
        // 如果找不到数据也出队
        clearInterval(interval);
        const processedRequest = requestQueues[queueIndex].shift();
        logger.info(
          `请求找不到对应数据已出队，SN: ${processedRequest.sn}，剩余队列${
            queueIndex + 1
          }长度: ${requestQueues[queueIndex].length}`
        );
        // 从轮询已处理集合中移除该SN
        pollingProcessedSNs[queueIndex].delete(processedRequest.sn);
        isProcessings[queueIndex] = false;

        // 清除该SN的缓存
        clearCacheForSN(
          processedRequest.sn,
          processedRequest.long,
          processedRequest.wide,
          processedRequest.height,
          processedRequest.beUsed
        );

        // 检查所有队列是否有待处理任务
        checkAllQueues();
      }
    } catch (error) {
      logger.error(`轮询检查状态时出错: ${error.message}`);
      clearInterval(interval);
      const processedRequest = requestQueues[queueIndex].shift();
      logger.info(
        `轮询出错，请求已出队，SN: ${processedRequest?.sn || "未知"}，剩余队列${
          queueIndex + 1
        }长度: ${requestQueues[queueIndex].length}`
      );
      // 从轮询已处理集合中移除该SN
      if (processedRequest && processedRequest.sn) {
        pollingProcessedSNs[queueIndex].delete(processedRequest.sn);
      }
      isProcessings[queueIndex] = false;

      // 清除该SN的缓存
      if (processedRequest) {
        clearCacheForSN(
          processedRequest.sn,
          processedRequest.long,
          processedRequest.wide,
          processedRequest.height,
          processedRequest.beUsed
        );
      }

      // 检查所有队列是否有待处理任务
      checkAllQueues();
    }
  }, POLLING_INTERVAL); // 使用合理的检查间隔
}

// 获取sn 对应的产品信息
async function getData(data) {
  let proInfo = data;
  const proData = {
    id: proInfo.id,
    long: proInfo.long,
    wide: proInfo.wide,
    height: proInfo.height,
    presetNum: proInfo.presetNum,
    layerNum: proInfo.layerNum,
    palletizingNum: proInfo.palletizingNum,
    userId: proInfo.userId,
    beUsed: proInfo.beUsed,
    userName: proInfo.userName,
    status: proInfo.status,
    lineName: proInfo.lineName,
    sizeRuleId: proInfo.sizeRuleId,
    weight: proInfo.weight,
    sn: proInfo.sn,
  };
  return proData;
}

// 接口请求 - 保持GET方式

router.get("/:sn/:long/:wide/:height/:beUsed", async (req, res, next) => {
  try {
    // 获取参数
    const { sn, long, wide, height, beUsed } = req.params;
    logger.info(
      `接收到请求参数: SN=${sn}, 长=${long}, 宽=${wide}, 高=${height}, beUsed=${beUsed}`
    );

    // 获取用户信息
    let { user } = await userInfo(req);

    // const requestData = {
    //   sn: sn,
    //   long: long,
    //   wide: wide,
    //   height: height,
    //   beUsed: parseInt(beUsed), // 确保beUsed是数字类型
    //   user,
    //   req,
    //   res,
    // };

    // await enqueueRequest(requestData);

    // // 检查所有队列，确保所有队列都能得到处理
    // checkAllQueues();
    //   return;

    // 获取托盘码开始
    const { count, rows } = await productionInfo(sn, long, wide, height);
    logger.info(`查询到产品信息: count=${count}`);
    if (count == 1) {
      if (rows[0].dataValues.status == 0) {
        const data = {
          startDeviceId:
            wcsData[rows[0].dataValues.beUsed + rows[0].dataValues.lineName]
              .startDeviceId,
        };

        logger.info(`准备获取托盘码: ${JSON.stringify(data)}`);

        plcManualOperationHandle(data).then(async (response) => {
          logger.info(`获取托盘码的response: ${JSON.stringify(response)}`);
          if (response.returnData.destStation2 == 1) {
            await updateProductionByIdToPalletCode(
              req,
              rows[0].dataValues.id,
              response.returnData.currentTaskNo
            );
            const requestData = {
              sn: sn,
              long: long,
              wide: wide,
              height: height,
              beUsed: parseInt(beUsed), // 确保beUsed是数字类型
              user,
              req,
              res,
            };

            await enqueueRequest(requestData);

            // 检查所有队列，确保所有队列都能得到处理
            checkAllQueues();
          } else {
            success(req, res, "没有可以使用的托盘码", {});
          }
        });
      } else {
        success(req, res, `商品编码为${sn}已经码垛过，无需再次码垛`, {});
      }
    } else {
      success(
        req,
        res,
        `没有找到sn 为${sn}、长为${long}、宽为${wide}、高为${height}的产品`,
        {}
      );
    }
    //获取托盘码结束;

    // const requestData = {
    //   sn: sn,
    //   long: long,
    //   wide: wide,
    //   height: height,
    //   beUsed: parseInt(beUsed), // 确保beUsed是数字类型
    //   user,
    //   req,
    //   res,
    // };

    // await enqueueRequest(requestData);

    // // 检查所有队列，确保所有队列都能得到处理
    // checkAllQueues();

    // const proDataList = await getAllProductions({
    //   limit: 32, // 限制每次获取100条记录
    //   offset: 0,
    //   where: {
    //     status: "0", // 只获取状态为1(已完成)的产品
    //   },
    // });

    // logger.info(`获取到 ${proDataList.length} 条产品数据`);

    // // 分批处理产品数据
    // const batchSize = 16; // 每批处理16个产品
    // for (let i = 0; i < proDataList.length; i += batchSize) {
    //   // 获取当前批次的产品数据
    //   let batch = [];
    //   if (proDataList.length < 16) {
    //     batch = proDataList;
    //   } else {
    //     batch = proDataList.slice(i, i + batchSize);
    //   }

    //   // 并行处理批次中的所有产品
    //   const enqueuePromises = batch.map(async (product) => {
    //     try {
    //       // 验证产品数据
    //       if (
    //         !product.sn ||
    //         !product.long ||
    //         !product.wide ||
    //         !product.height ||
    //         !product.beUsed
    //       ) {
    //         logger.warn(
    //           `产品数据不完整，跳过处理: ${JSON.stringify({
    //             id: product.id,
    //             sn: product.sn,
    //             long: product.long,
    //             wide: product.wide,
    //             height: product.height,
    //             beUsed: product.beUsed,
    //           })}`
    //         );
    //         return;
    //       }

    //       // 将请求参数加入队列
    //       const requestData = {
    //         sn: product.sn,
    //         long: product.long,
    //         wide: product.wide,
    //         height: product.height,
    //         beUsed: parseInt(product.beUsed, 10), // 确保beUsed是数字类型
    //         user,
    //         req,
    //         res,
    //       };

    //       await enqueueRequest(requestData);
    //     } catch (error) {
    //       logger.error(`处理产品 ${product.sn} 时发生错误: ${error.message}`);
    //     }
    //   });

    //   // 等待当前批次的所有产品入队完成
    //   await Promise.all(enqueuePromises);

    //   // 检查所有队列，确保所有队列都能得到处理
    //   checkAllQueues();

    //   // 添加一个小延迟，避免过于频繁的操作
    //   await new Promise((resolve) => setTimeout(resolve, 100));
    // }

    // logger.info(
    //   `完成所有产品数据的队列处理，共处理 ${proDataList.length} 条产品数据`
    // );
  } catch (error) {
    logger.error(`处理请求时发生错误: ${error.message}`);
    failure(req, res, error);
  }
});

// 获取产品对应的设备信息【plc 和相机】
async function getProduction(req, sn, id, socket, proData) {
  try {
    let content = "正在进行处理";
    logger.info(`开始获取产品对应的设备信息，SN: ${sn}`);
    // 获取满足条件的设备ip信息；根据beUsed 筛选
    const { count: countIpInfo, rows: rowsIpInfo } = await ipInfoSingle(
      proData.beUsed
    );
    logger.info(`查询到IP信息: count=${countIpInfo}`);
    // 没有找到设备IP信息
    if (countIpInfo == 0) {
      content = "没有找到该sn码对应的ip设备信息";
      // 异步发送消息，不阻塞主流程
      setSocket(socket, "码垛信息", content, id, sn).catch((err) => {
        logger.error(`发送Socket消息失败: ${err.message}`);
      });
      logger.info(`${content}`);
      return;
    }

    // 过滤rowsInpInfo 中的type 是2的数据 得到plc 设备的信息
    const ipPlcData = rowsIpInfo.filter((item) => item.dataValues.type == 2);
    // 获取相机设备的ip信息 并筛选出beUsed 和产品对应的数据
    const ipCameraData = rowsIpInfo.filter(
      (item) =>
        item.dataValues.type == 1 && item.dataValues.beUsed == proData.beUsed
    );

    let client = null;
    let cameraData;
    if (ipCameraData.length == 0) {
      content = "没有找到该sn码对应的摄像头信息";
      logger.info(`${content}`);
      // 异步发送消息，不阻塞主流程
      setSocket(socket, "码垛信息", content, id, sn).catch((err) => {
        logger.error(`发送Socket消息失败: ${err.message}`);
      });
      return;
    }

    cameraData = ipCameraData[0].dataValues;
    // 查看相机ip连接的列表中，是否有和产品对应的相机
    client = tcpClients.find((c) => c.id === cameraData.id);

    const obj = {
      id: cameraData.id,
      ip: cameraData.ip,
      port: cameraData.port,
      type: cameraData.type,
    };
    if (!client) {
      content = "没有建立相机连接";
      logger.info(`${content}`);
      // 异步发送消息，不阻塞主流程
      setSocket(socket, "码垛信息", content, id, "").catch((err) => {
        logger.error(`发送Socket消息失败: ${err.message}`);
      });
      return;
    }
    if (client.status == "1") {
      content = "相机连接中";
      logger.info(`${content}`);
      // 异步发送消息，不阻塞主流程
      setSocket(socket, "码垛信息", content, id, JSON.stringify(obj)).catch(
        (err) => {
          logger.error(`发送Socket消息失败: ${err.message}`);
        }
      );
    } else {
      content = "相机未连接";
      logger.info(`${content}`);
      // 异步发送消息，不阻塞主流程
      setSocket(socket, "码垛信息", content, id, JSON.stringify(obj)).catch(
        (err) => {
          logger.error(`发送Socket消息失败: ${err.message}`);
        }
      );
    }

    // 处理plc相机状态
    if (ipPlcData.length == 0) {
      content = "查找找该sn码对应的plc信息失败";
      logger.info(`${content}`);
      // 异步发送消息，不阻塞主流程
      setSocket(socket, "码垛信息", content, id, sn).catch((err) => {
        logger.error(`发送Socket消息失败: ${err.message}`);
      });
      return;
    }

    content = "查找sn对应的plc信息成功";
    logger.info(`${content}`);
    // 异步发送消息，不阻塞主流程
    setSocket(socket, "码垛信息", content, id, sn).catch((err) => {
      logger.error(`发送Socket消息失败: ${err.message}`);
    });

    // 如果相机的状态是连接中，那么就可以进行拍照
    if (client.status == 1) {
      // 异步执行plcArrivalSignal，不阻塞主流程
      plcArrivalSignal(
        req,
        sn,
        id,
        socket,
        proData,
        ipPlcData[0].dataValues,
        cameraData,
        client
      ).catch((error) => {
        logger.error(`plcArrivalSignal执行出错: ${error.message}`);
      });
    }
  } catch (error) {
    logger.error(`getProduction函数执行出错: ${error.message}`);
    throw error; // 将错误抛出，让调用者处理
  }
}

// 检查所有队列是否有待处理任务
function checkAllQueues() {
  // 使用Promise.all并行处理所有队列的检查
  const processPromises = [];
  logger.info(
    `检查所有队列，当前队列状态: ${JSON.stringify(
      requestQueues.map((q, i) => ({
        queue: i + 1,
        length: q.length,
        processing: isProcessings[i],
      }))
    )}`
  );
  for (let i = 0; i < requestQueues.length; i++) {
    if (!isProcessings[i] && requestQueues[i].length > 0) {
      // 使用立即执行函数确保每个队列的处理是独立的
      const processPromise = new Promise((resolve) => {
        setImmediate(() => {
          processNextRequest(i).then(resolve).catch(resolve);
        });
      });
      processPromises.push(processPromise);
    }
  }

  // 不等待处理完成，直接返回，确保所有队列可以并行处理
  Promise.all(processPromises).catch((err) => {
    logger.error(`处理队列时发生错误: ${err.message}`);
  });
}

// 清除指定SN的缓存
function clearCacheForSN(sn, long, wide, height, beUsed) {
  const cacheKey = `${sn}-${long}-${wide}-${height}-${beUsed}`;
  if (productInfoCache.has(cacheKey)) {
    productInfoCache.delete(cacheKey);
    logger.info(`已清除SN: ${sn} 的缓存数据`);
  }
}

module.exports = router;
